﻿using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RantLEDOCR.Common
{
    class LedDigitRecognizer:IDisposable
    {
        private Dictionary<char, Mat> templates = new Dictionary<char, Mat>();
        private string templateFolder = "Templates";

        // 构造函数：加载模板
        public LedDigitRecognizer()
        {
            LoadTemplates();
        }

        // 加载数字模板
        private void LoadTemplates()
        {
            if (!Directory.Exists(templateFolder))
            {
                Console.WriteLine($"模板文件夹 {templateFolder} 不存在！");
                return;
            }

            // 加载0-9的模板
            for (char c = '0'; c <= '9'; c++)
            {
                string templatePath = Path.Combine(templateFolder, $"{c}.png");
                if (File.Exists(templatePath))
                {
                    Mat template = new Mat(templatePath, ImreadModes.Grayscale);
                    if (!template.Empty())
                    {
                        templates[c] = template;
                    }
                }
            }
        }

        // 预处理图像
        private Mat PreprocessImage(Mat src)
        {
            Mat gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);

            Mat blurred = new Mat();
            Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0);

            Mat thresholded = new Mat();
            Cv2.Threshold(blurred, thresholded, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);

            return thresholded;
        }

        // 寻找数字轮廓并识别
        public string RecognizeDigits(Mat src)
        {
            Mat processed = PreprocessImage(src);
            Mat contoursImage = processed.Clone();

            Cv2.FindContours(contoursImage, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);

            // 根据轮廓面积过滤并排序
            var digitContours = contours
                .Where(c => Cv2.ContourArea(c) > 100 && Cv2.ContourArea(c) < 10000)
                .OrderBy(c => Cv2.BoundingRect(c).X)
                .ToList();

            string recognizedDigits = "";

            foreach (var contour in digitContours)
            {
                Rect boundingRect = Cv2.BoundingRect(contour);
                Mat digitROI = processed.SubMat(boundingRect);

                // 调整ROI大小以匹配模板
                Mat resizedROI = new Mat();
                Cv2.Resize(digitROI, resizedROI, new Size(20, 30));

                char recognizedDigit = RecognizeDigit(resizedROI);
                recognizedDigits += recognizedDigit;

                // 在原图上绘制识别结果
                Cv2.Rectangle(src, boundingRect, new Scalar(0, 255, 0), 2);
                Cv2.PutText(src, recognizedDigit.ToString(), new OpenCvSharp.Point(boundingRect.X, boundingRect.Y - 10), HersheyFonts.HersheySimplex, 1, new Scalar(0, 255, 0), 2);
            }

            return recognizedDigits;
        }

        // 识别单个数字
        private char RecognizeDigit(Mat digitROI)
        {
            char bestMatch = '?';
            double minDiff = double.MaxValue;

            foreach (var template in templates)
            {
                Mat result = new Mat();
                Cv2.MatchTemplate(digitROI, template.Value, result, TemplateMatchModes.SqDiff);

                Cv2.MinMaxLoc(result, out double minVal, out double maxVal, out OpenCvSharp.Point minLoc, out OpenCvSharp.Point maxLoc);

                if (minVal < minDiff)
                {
                    minDiff = minVal;
                    bestMatch = template.Key;
                }
            }

            return bestMatch;
        }

        // 保存模板（用于创建模板库）
        public void SaveTemplate(Mat digitROI, char digit)
        {
            if (!Directory.Exists(templateFolder))
            {
                Directory.CreateDirectory(templateFolder);
            }

            string templatePath = Path.Combine(templateFolder, $"{digit}.png");
            Mat resizedROI = new Mat();
            Cv2.Resize(digitROI, resizedROI, new Size(20, 30));
            Cv2.ImWrite(templatePath, resizedROI);
        }

        // 释放资源
        public void Dispose()
        {
            foreach (var template in templates.Values)
            {
                template.Dispose();
            }
        }
    }

   
}
